package jee.boot.module.elasticsearch.utils;

import jee.boot.common.basic.ServiceException;
import jee.boot.common.utils.JsonMapper;
import jee.boot.common.utils.SpringContextHolder;
import jee.boot.common.utils.StringUtils;
import jee.boot.module.elasticsearch.entity.Document;
import jee.boot.module.elasticsearch.entity.Index;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Elasticsearch工具类
 */
public class ElasticsearchUtils {
    private static final Logger logger = LoggerFactory.getLogger(ElasticsearchUtils.class);
    private static RestHighLevelClient highLevelClient;
//    private static RestHighLevelClient highLevelClient = new RestHighLevelClient(
//            RestClient.builder(
//                    new HttpHost("192.168.56.101", 9200, "http")
//            ));

    /**
     * 新建索引
     *
     * @param index
     * @return
     */
    public static boolean createIndex(Index index) {
        if (index == null) {
            return false;
        }
        CreateIndexRequest request = new CreateIndexRequest(index.getName());//创建索引
        //创建索引时创建文档类型映射
        request.mapping(JsonMapper.toJsonString(index.getMapping()), XContentType.JSON);
        if (StringUtils.isNotBlank(index.getAlias())) {
            //为索引设置一个别名
            request.alias(new Alias(index.getAlias()));
        }

        //同步执行
        RequestOptions options = RequestOptions.DEFAULT;
        CreateIndexResponse createIndexResponse = null;
        try {
            createIndexResponse = getHighLevelClient().indices().create(request, options);
            //返回的CreateIndexResponse允许检索有关执行的操作的信息，如下所示：
            boolean acknowledged = createIndexResponse.isAcknowledged();//指示是否所有节点都已确认请求
            return acknowledged;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    /**
     * 更新索引Mapping
     * <br>
     * 注意,这里提供的Mapping应该为全量的Mapping,而非增量的Mapping
     *
     * @param index
     * @return
     */
    public static boolean updateIndexMapping(Index index) {
        if (index == null) {
            return false;
        }
        PutMappingRequest request = new PutMappingRequest(index.getName());//指定要更新的索引名称
        //设置IndicesOptions控制如何解决不可用的索引以及如何扩展通配符表达式
        request.indicesOptions(IndicesOptions.lenientExpandOpen());
        request.source(JsonMapper.toJsonString(index.getMapping()), XContentType.JSON);
        RequestOptions options = RequestOptions.DEFAULT;
        //同步执行
        AcknowledgedResponse updateIndexResponse = null;
        try {
            updateIndexResponse = getHighLevelClient().indices().putMapping(request, options);
            //Close Index Response
            //返回的CloseIndexResponse 允许检索有关执行的操作的信息，如下所示：
            boolean acknowledged = updateIndexResponse.isAcknowledged();///指示是否所有节点都已确认请求
            return acknowledged;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    /**
     * 删除索引
     *
     * @param index
     */
    public static boolean deleteIndex(Index index) {
        if (index == null) {
            return false;
        }
        DeleteIndexRequest request = new DeleteIndexRequest(index.getName());//指定要删除的索引名称
        //设置IndicesOptions控制如何解决不可用的索引以及如何扩展通配符表达式
        request.indicesOptions(IndicesOptions.lenientExpandOpen());
        RequestOptions options = RequestOptions.DEFAULT;
        //同步执行
        AcknowledgedResponse deleteIndexResponse = null;
        try {
            deleteIndexResponse = getHighLevelClient().indices().delete(request, options);
            //Delete Index Response
            //返回的DeleteIndexResponse允许检索有关执行的操作的信息，如下所示：
            boolean acknowledged = deleteIndexResponse.isAcknowledged();//是否所有节点都已确认请求
            return acknowledged;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    /**
     * 打开索引
     *
     * @param index
     * @return
     */
    public static boolean openIndex(Index index) {
        if (index == null) {
            return false;
        }
        OpenIndexRequest request = new OpenIndexRequest(index.getName());//指定要删除的索引名称
        //设置IndicesOptions控制如何解决不可用的索引以及如何扩展通配符表达式
        request.indicesOptions(IndicesOptions.lenientExpandOpen());
        RequestOptions options = RequestOptions.DEFAULT;
        //同步执行
        OpenIndexResponse openIndexResponse = null;
        try {
            openIndexResponse = getHighLevelClient().indices().open(request, options);
            //Open Index Response
            //返回的OpenIndexResponse允许检索有关执行的操作的信息，如下所示：
            boolean acknowledged = openIndexResponse.isAcknowledged();///指示是否所有节点都已确认请求
            return acknowledged;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    /**
     * 关闭索引
     *
     * @param index
     * @return
     */
    public static boolean closeIndex(Index index) {
        if (index == null) {
            return false;
        }
        CloseIndexRequest request = new CloseIndexRequest(index.getName());//指定要删除的索引名称
        //设置IndicesOptions控制如何解决不可用的索引以及如何扩展通配符表达式
        request.indicesOptions(IndicesOptions.lenientExpandOpen());
        RequestOptions options = RequestOptions.DEFAULT;
        //同步执行
        AcknowledgedResponse closeIndexResponse = null;
        try {
            closeIndexResponse = getHighLevelClient().indices().close(request, options);
            //Close Index Response
            //返回的CloseIndexResponse 允许检索有关执行的操作的信息，如下所示：
            boolean acknowledged = closeIndexResponse.isAcknowledged();///指示是否所有节点都已确认请求

            return acknowledged;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }
    /*--------------------------Single document APIs--------------------*/

    /**
     * 添加数据
     *
     * @param data
     * @return
     */
    public static boolean save(Document data) {
        IndexRequest indexRequest = new IndexRequest(data.getIndexName());
        indexRequest.source(data.getData());
        RequestOptions options = RequestOptions.DEFAULT;
        //===============================执行====================================
        //同步执行
        try {
            IndexResponse indexResponse = getHighLevelClient().index(indexRequest, options);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    /**
     * 修改数据
     *
     * @param data
     * @return
     */
    public static boolean update(Document data) {
        UpdateRequest updateRequest = new UpdateRequest(data.getIndexName(), data.getId());
        updateRequest.doc(data.getData());
        RequestOptions options = RequestOptions.DEFAULT;
        //===============================执行====================================
        //同步执行
        try {
            UpdateResponse updateResponse = getHighLevelClient().update(updateRequest, options);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    /**
     * 删除数据
     *
     * @param data
     * @return
     */
    public static boolean delete(Document data) {
        DeleteRequest deleteRequest = new DeleteRequest(data.getIndexName(), data.getId());
        RequestOptions options = RequestOptions.DEFAULT;
        //===============================执行====================================
        //同步执行
        try {
            DeleteResponse updateResponse = getHighLevelClient().delete(deleteRequest, options);
            return true;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    /**
     * 查看数据
     *
     * @param data
     * @return
     */
    public static GetResponse get(Document data) {
        GetRequest getRequest = new GetRequest(data.getIndexName(), data.getId());
        RequestOptions options = RequestOptions.DEFAULT;
        //===============================执行====================================
        //同步执行
        try {
            GetResponse getResponse = getHighLevelClient().get(getRequest, options);
            return getResponse;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    /*--------------------------Search document APIs--------------------*/

    /**
     * 基于拼接的查询字符串进行查询,可以手动拼接标准的查询参数进行查询
     *
     * @param data
     * @return
     */
    public static SearchResponse search(Document data) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        if(data.getQuery()==null){
            searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        }else{
            searchSourceBuilder.query(QueryBuilders.queryStringQuery(JsonMapper.toJsonString(data.getQuery())));
        }

        return search(data, searchSourceBuilder);
    }

    /**
     * 基于SearchSourceBuilder进行查询,可以手动编写查询的api进行查询
     *
     * @param data
     * @return
     */
    public static SearchResponse search(Document data, SearchSourceBuilder searchSourceBuilder) {
        SearchRequest searchRequest = new SearchRequest(data.getIndexName());
        searchRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
        RequestOptions options = RequestOptions.DEFAULT;
        searchRequest.source(searchSourceBuilder);
        //===============================执行====================================
        //同步执行
        try {
            SearchResponse searchResponse = getHighLevelClient().search(searchRequest, options);
            return searchResponse;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new ServiceException();
        }
    }

    public static RestHighLevelClient getHighLevelClient() {
        if(highLevelClient==null){
            highLevelClient= SpringContextHolder.getBean(RestHighLevelClient.class);
        }
        return highLevelClient;
    }
}
